package com.qqim.server;

import com.qqim.common.entity.Message;
import com.qqim.common.entity.User;
import com.qqim.common.protocol.Protocol;
import com.qqim.common.utils.JsonUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 客户端处理器
 */
public class ClientHandler implements Runnable {
    private static final Logger logger = LoggerFactory.getLogger(ClientHandler.class);
    
    private final Socket clientSocket;
    private final QQIMServer server;
    
    private BufferedReader reader;
    private PrintWriter writer;
    
    private String userId;
    private volatile boolean running = true;
    
    public ClientHandler(Socket clientSocket, QQIMServer server) {
        this.clientSocket = clientSocket;
        this.server = server;
        
        try {
            this.reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream(), "UTF-8"));
            this.writer = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), "UTF-8"), true);
        } catch (IOException e) {
            logger.error("创建客户端处理器失败", e);
            close();
        }
    }
    
    @Override
    public void run() {
        try {
            String line;
            while (running && (line = reader.readLine()) != null) {
                handleMessage(line);
            }
        } catch (IOException e) {
            if (running) {
                logger.error("客户端通信异常: {}", clientSocket.getRemoteSocketAddress(), e);
            }
        } finally {
            cleanup();
        }
    }
    
    /**
     * 处理接收到的消息
     */
    private void handleMessage(String message) {
        try {
            Protocol protocol = JsonUtils.fromJson(message, Protocol.class);
            if (protocol == null) {
                logger.info("接收到无效消息: {}", message);
                return;
            }
            
            logger.debug("接收到消息: {}", protocol.getType());
            
            switch (protocol.getType()) {
                case Protocol.LOGIN:
                    handleLogin(protocol);
                    break;
                    
                case Protocol.LOGOUT:
                    handleLogout(protocol);
                    break;
                    
                case Protocol.GET_USER_LIST:
                    handleGetUserList();
                    break;
                    
                case Protocol.SEND_MESSAGE:
                    handleSendMessage(protocol);
                    break;
                    
                case Protocol.SEND_IMAGE:
                    handleSendImage(protocol);
                    break;
                    
                case Protocol.HEARTBEAT:
                    handleHeartbeat(protocol);
                    break;
                    
                default:
                    logger.info("未知的协议类型: {}", protocol.getType());
                    break;
            }
            
        } catch (Exception e) {
            logger.error("处理消息失败: {}", message, e);
        }
    }
    
    /**
     * 处理用户登录
     */
    private void handleLogin(Protocol protocol) {
        String requestUserId = protocol.getSenderId();
        String nickname = (String) protocol.getData();
        
        logger.debug("处理登录请求 - 用户ID: {}, 昵称: {}", requestUserId, nickname);
        
        if (requestUserId == null || requestUserId.trim().isEmpty()) {
            logger.info("登录失败 - 用户ID为空");
            sendMessage(Protocol.loginFailed("用户ID不能为空"));
            return;
        }
        
        if (nickname == null || nickname.trim().isEmpty()) {
            logger.info("登录失败 - 昵称为空");
            sendMessage(Protocol.loginFailed("用户昵称不能为空"));
            return;
        }
        
        // 尝试登录
        logger.debug("尝试用户登录: {} [{}]", nickname, requestUserId);
        boolean success = server.userLogin(requestUserId, nickname, this);
        if (success) {
            this.userId = requestUserId;
            logger.info("用户登录成功: {} [{}]", nickname, requestUserId);
            sendMessage(Protocol.loginSuccess(requestUserId));
            
            // 发送在线用户列表
            sendUserList();
        } else {
            logger.info("用户登录失败: {} [{}] - 用户已在线或其他错误", nickname, requestUserId);
            sendMessage(Protocol.loginFailed("用户已在线或登录失败"));
        }
    }
    
    /**
     * 处理用户登出
     */
    private void handleLogout(Protocol protocol) {
        if (userId != null) {
            server.userLogout(userId);
            userId = null;
        }
        close();
    }
    
    /**
     * 处理获取用户列表请求
     */
    private void handleGetUserList() {
        sendUserList();
    }
    
    /**
     * 发送用户列表
     */
    private void sendUserList() {
        ConcurrentHashMap<String, User> onlineUsers = server.getOnlineUsers();
        sendMessage(Protocol.userList(onlineUsers));
    }
    
    /**
     * 处理发送消息
     */
    private void handleSendMessage(Protocol protocol) {
        String senderId = protocol.getSenderId();
        String receiverId = protocol.getReceiverId();
        
        if (!senderId.equals(userId)) {
            logger.info("用户尝试冒充其他用户发送消息: {} -> {}", userId, senderId);
            return;
        }
        
        if (receiverId == null || receiverId.trim().isEmpty()) {
            logger.info("消息接收者为空");
            return;
        }
        
        // 转发消息
        Protocol forwardProtocol = Protocol.receiveMessage(senderId, receiverId, protocol.getData());
        server.forwardMessage(senderId, receiverId, forwardProtocol);
    }
    
    /**
     * 处理发送图片
     */
    private void handleSendImage(Protocol protocol) {
        String senderId = protocol.getSenderId();
        String receiverId = protocol.getReceiverId();
        
        if (!senderId.equals(userId)) {
            logger.info("用户尝试冒充其他用户发送图片: {} -> {}", userId, senderId);
            return;
        }
        
        if (receiverId == null || receiverId.trim().isEmpty()) {
            logger.info("图片接收者为空");
            return;
        }
        
        // 转发图片
        Protocol forwardProtocol = Protocol.receiveImage(senderId, receiverId, protocol.getData());
        server.forwardMessage(senderId, receiverId, forwardProtocol);
    }
    
    /**
     * 处理心跳
     */
    private void handleHeartbeat(Protocol protocol) {
        // 简单响应心跳
        sendMessage(Protocol.heartbeat(userId));
    }
    
    /**
     * 发送消息给客户端
     */
    public void sendMessage(Protocol protocol) {
        if (writer != null) {
            String message = JsonUtils.toJson(protocol);
            if (message != null) {
                writer.println(message);
                logger.debug("发送消息给客户端: {}, 内容: {}", protocol.getType(), message);
            } else {
                logger.error("JSON序列化失败, protocol: {}", protocol);
            }
        } else {
            logger.error("Writer为null，无法发送消息: {}", protocol.getType());
        }
    }
    
    /**
     * 关闭连接
     */
    public void close() {
        running = false;
        
        try {
            if (reader != null) {
                reader.close();
            }
        } catch (IOException e) {
            logger.error("关闭输入流失败", e);
        }
        
        if (writer != null) {
            writer.close();
        }
        
        try {
            if (clientSocket != null && !clientSocket.isClosed()) {
                clientSocket.close();
            }
        } catch (IOException e) {
            logger.error("关闭客户端Socket失败", e);
        }
    }
    
    /**
     * 清理资源
     */
    private void cleanup() {
        if (userId != null) {
            server.userLogout(userId);
        }
        close();
    }
    
    /**
     * 获取客户端地址
     */
    public String getClientAddress() {
        if (clientSocket != null) {
            return clientSocket.getRemoteSocketAddress().toString();
        }
        return "unknown";
    }
    
    /**
     * 获取用户ID
     */
    public String getUserId() {
        return userId;
    }
    
    /**
     * 检查连接是否活跃
     */
    public boolean isConnected() {
        return running && clientSocket != null && !clientSocket.isClosed();
    }
} 